package com.syh.jn.scm.service.impl.supplier.finance;

import com.alibaba.dubbo.config.annotation.Service;
import com.syh.core.ddd.event.annotation.DomainEventHandle;
import com.syh.core.ddd.infrastructure.repository.AggregateRepository;
import com.syh.core.ddd.service.AbstractServiceImpl;
import com.syh.jn.scm.domain.supplier.entity.finance.*;
import com.syh.jn.scm.domain.supplier.event.PaymentBillEvent;
import com.syh.jn.scm.domain.supplier.event.finance.PurchaseInvoiceEvent;
import com.syh.jn.scm.domain.supplier.event.finance.ReceiptBillEvent;
import com.syh.jn.scm.domain.supplier.event.finance.SalesInvoiceEvent;
import com.syh.jn.scm.domain.supplier.event.finance.StatementAccountBillEvent;
import com.syh.jn.scm.domain.supplier.repository.finance.StatementAccountBillRepository;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillItemVo;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillMto;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillSto;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillVo;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.service.api.supplier.finance.StatementAccountBillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * 对账单功能接口实现
 */
@Service
@Transactional
public class StatementAccountBillServiceImpl extends AbstractServiceImpl<StatementAccountBillSto, StatementAccountBillMto, StatementAccountBillVo, StatementAccountBill, Long> implements StatementAccountBillService {

  @Autowired
  private StatementAccountBillRepository statementOfAccountBillRepositoryImpl;

  @Override
  protected AggregateRepository<StatementAccountBill, Long> getAggregateRepository() {
    return statementOfAccountBillRepositoryImpl;
  }

  /**
   * 保存对账单
   *
   * @param sto
   * @return
   */
  @Override
  public Long save(StatementAccountBillSto sto) {
    StatementAccountBill bill = new StatementAccountBill(sto);
    Long id = statementOfAccountBillRepositoryImpl.add(bill);
    bill.setId(id);

    this.publicEvent(StatementAccountBillEvent.buildStatementBillAccountCreated(new Object[]{bill}));
    return id;
  }

  @Override
  public void update(StatementAccountBillMto mto) {
    StatementAccountBill statementAccountBill = statementOfAccountBillRepositoryImpl.getById(mto.getId());
    statementAccountBill.modify(mto);
    statementOfAccountBillRepositoryImpl.update(statementAccountBill);
    this.publicEvent(StatementAccountBillEvent.buildStatementBillAccountUpdata(new Object[]{statementAccountBill}));

  }

  /**
   * 删除对账单
   *
   * @param id
   */
  @Override
  public void delete(Long id) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(id);
    bill.destroy();
    this.publicEvent(StatementAccountBillEvent.buildStatementBillAccountDestroy(new Object[]{bill}));
    statementOfAccountBillRepositoryImpl.remove(bill);
  }


  /**
   * 业务确认
   *
   * @param id
   */
  @Override
  public void businessConfirmation(Long id) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(id);
    bill.businessConfirmation();
    statementOfAccountBillRepositoryImpl.update(bill);
  }

  /**
   * 业务取消确认
   *
   * @param id
   */
  @Override
  public void businessCancelConfirmation(Long id) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(id);
    bill.businessCancelConfirmation();
    statementOfAccountBillRepositoryImpl.update(bill);
  }

  /**
   * 财务确认
   *
   * @param id
   */
  @Override
  public void financeConfirmation(Long id) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(id);
    bill.financeConfirmation();
    statementOfAccountBillRepositoryImpl.update(bill);
  }

  /**
   * 财务取消确认
   *
   * @param id
   */
  @Override
  public void financeCancelConfirmation(Long id) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(id);
    bill.financeCancelConfirmation();
    statementOfAccountBillRepositoryImpl.update(bill);
  }

  /**
   * 上传单据图片
   *
   * @param dto
   */
  @Override
  public void uploadImg(FilesDto dto) {
    StatementAccountBill bill = statementOfAccountBillRepositoryImpl.getById(dto.getId());
    bill.uploadImages(dto);
    statementOfAccountBillRepositoryImpl.uploadImages(bill);
  }

  /**
   * 根据对账单id获取明细
   *
   * @param statementId 对账单id
   * @return
   */
  @Override
  public List<StatementAccountBillItemVo> getItemsByStatementId(Long statementId) {
    List<StatementAccountBillItemVo> statementAccountBillItemVos = statementOfAccountBillRepositoryImpl.getItemsByStatementId(statementId);
    return statementAccountBillItemVos;
  }

  /**
   * 监听付款单事件
   *
   * @param bill
   */
  @DomainEventHandle(PaymentBillEvent.PAYMENT_BILL_LOCK)
  protected void handlePaymentBillConfirmEvent(PaymentBill bill) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(bill.getStatementOfAccountId());
    billState.addMakeCollectionsPrice(bill.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 监听付款单事件(取消付款)
   *
   * @param bill
   */
  @DomainEventHandle(PaymentBillEvent.PAYMENT_BILL_UNLOCK)
  protected void handlePaymentBillCancelEvent(PaymentBill bill) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(bill.getStatementOfAccountId());
    billState.subMakeCollectionsPrice(bill.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 监听收款单事件
   *
   * @param bill
   */
  @DomainEventHandle(ReceiptBillEvent.RECEIPT_BILL_LOCK)
  protected void handleStatementBillAccountPayEvent(ReceiptBill bill) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(bill.getStatementOfAccountId());
    billState.addMakeCollectionsPrice(bill.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 监听收款单取消到账事件
   *
   * @param bill
   */
  @DomainEventHandle(ReceiptBillEvent.RECEIPT_BILL_UNLOCK)
  protected void handleStatementBillAccountCancelPayEvent(ReceiptBill bill) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(bill.getStatementOfAccountId());
    billState.subMakeCollectionsPrice(bill.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 消费者：监听销项发票 确认签收发票
   *
   * @param invoice
   */
  @DomainEventHandle(SalesInvoiceEvent.SALES_INVOICE_CONFIRM)
  protected void handleSalesInvoiceConfirmEvent(SalesInvoice invoice) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(invoice.getStatementOfAccountId());
    billState.addTicketPrice(invoice.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 消费者：监听销项发票 取消确认发票
   *
   * @param invoice
   */
  @DomainEventHandle(SalesInvoiceEvent.SALES_INVOICE_UNCONFIRM)
  protected void handleSalesInvoiceUnconfirmEvent(SalesInvoice invoice) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(invoice.getStatementOfAccountId());
    billState.subTicketPrice(invoice.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 消费者：监听进项发票 确认发票
   *
   * @param invoice
   */
  @DomainEventHandle(PurchaseInvoiceEvent.PURCHASE_INVOICE_CONFIRM)
  protected void handlePurchaseInvoiceConfirmEvent(PurchaseInvoice invoice) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(invoice.getStatementOfAccountId());
    billState.addTicketPrice(invoice.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 消费者：监听进项发票 取消确认、删除
   *
   * @param invoice
   */
  @DomainEventHandle({PurchaseInvoiceEvent.PURCHASE_INVOICE_UNCONFIRM})
  protected void handlePurchaseInvoiceUnconfirmEvent(PurchaseInvoice invoice) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(invoice.getStatementOfAccountId());
    billState.subTicketPrice(invoice.getPrice());
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 监听付款单创建事件（记录已生成收付款单金额）
   *
   * @param bill
   */
  @DomainEventHandle({PaymentBillEvent.PAYMENT_BILL_CREATED})
  protected void handlePaymentBillCreatedEvent(PaymentBill bill) {
    this.updateCeneratedCollectionsPrice(bill.getStatementOfAccountId(), bill.getPrice(), true);
  }

  /**
   * 监听付款单删除事件（记录已生成收付款单金额）
   *
   * @param bill
   */
  @DomainEventHandle({PaymentBillEvent.PAYMENT_BILL_DESTORY})
  protected void handlePaymentBillDestoryEvent(PaymentBill bill) {
    this.updateCeneratedCollectionsPrice(bill.getStatementOfAccountId(), bill.getPrice(), false);
  }

  /**
   * 监听收款单创建事件（记录已生成收付款单金额）
   *
   * @param bill
   */
  @DomainEventHandle(ReceiptBillEvent.RECEIPT_BILL_CREATED)
  protected void handleReceiptBillCreatedEvent(ReceiptBill bill) {
    this.updateCeneratedCollectionsPrice(bill.getStatementOfAccountId(), bill.getPrice(), true);
  }

  /**
   * 监听收款单删除事件（记录已生成收付款单金额）
   *
   * @param bill
   */
  @DomainEventHandle(ReceiptBillEvent.RECEIPT_BILL_DESTORY)
  protected void handleReceiptBillDestoryEvent(ReceiptBill bill) {
    this.updateCeneratedCollectionsPrice(bill.getStatementOfAccountId(), bill.getPrice(), false);
  }

  /**
   * 更新对账单已生成收付款单金额
   *
   * @param statementId
   * @param price
   * @param isAdd
   */
  private void updateCeneratedCollectionsPrice(Long statementId, BigDecimal price, boolean isAdd) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(statementId);
    if (isAdd) {
      billState.addGeneratedCollectionsPrice(price);
    } else {
      billState.subGeneratedCollectionsPrice(price);
    }
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 监听销项发票创建事件（记录已生成收付款单金额）
   *
   * @param salesInvoice
   */
  @DomainEventHandle(SalesInvoiceEvent.SALES_INVOICE_CREATED)
  protected void handleSalesInvoiceCreatedEvent(SalesInvoice salesInvoice) {
    this.updateCeneratedTicketPrice(salesInvoice.getStatementOfAccountId(), salesInvoice.getPrice(), true);
  }

  /**
   * 监听销项发票修改事件（记录已生成收付款单金额）
   * @param oldSalesInvoice
   * @param newSalesInvoice
   */
  //TODO 暂不考虑修改情况
//  @DomainEventHandle(SalesInvoiceEvent.SALES_INVOICE_UPDATE)
//  protected void handleSalesInvoiceUpdatedEvent(SalesInvoice oldSalesInvoice, SalesInvoice newSalesInvoice) {
//    StatementAccountBill statementAccountBill = statementOfAccountBillRepositoryImpl.getById(newSalesInvoice.getStatementOfAccountId());
//    statementAccountBill.subGeneratedTicketPrice(oldSalesInvoice.getPrice());
//    statementAccountBill.addGeneratedTicketPrice(newSalesInvoice.getPrice());
//    statementOfAccountBillRepositoryImpl.update(statementAccountBill);
//  }

  /**
   * 监听销项发票删除事件（记录已生成收付款单金额）
   *
   * @param salesInvoice
   */
  @DomainEventHandle(SalesInvoiceEvent.SALES_INVOICE_DESTROY)
  protected void handleSalesInvoiceDestoryEvent(SalesInvoice salesInvoice) {
    this.updateCeneratedTicketPrice(salesInvoice.getStatementOfAccountId(), salesInvoice.getPrice(), false);
  }


  /**
   * 更新对账单已生成开票金额
   *
   * @param statementId
   * @param price
   * @param isAdd
   */
  private void updateCeneratedTicketPrice(Long statementId, BigDecimal price, boolean isAdd) {
    StatementAccountBill billState = statementOfAccountBillRepositoryImpl.getById(statementId);
    if (isAdd) {
      billState.addGeneratedTicketPrice(price);
    } else {
      billState.subGeneratedTicketPrice(price);
    }
    statementOfAccountBillRepositoryImpl.update(billState);
  }

  /**
   * 消费者：监听进项发票删除（修改对账单已生成开票金额）
   *
   * @param purchaseInvoice
   */
  @DomainEventHandle(PurchaseInvoiceEvent.PURCHASE_INVOICE_DESTROY)
  protected void handleStatementBillAccountPurchaseInvoiceDestoryEvent(PurchaseInvoice purchaseInvoice) {
    StatementAccountBill statementAccountBill = statementOfAccountBillRepositoryImpl.getById(purchaseInvoice.getStatementOfAccountId());
    statementAccountBill.subGeneratedTicketPrice(purchaseInvoice.getPrice());
    statementOfAccountBillRepositoryImpl.update(statementAccountBill);
  }
}
